package CP2013Server;

import cp2013.Item;
import cp2013.User;

import java.io.*;
import java.net.*;
import java.util.*;
import java.text.SimpleDateFormat;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;

/**
 *
 * @author AcerXPS
 */
public class AuctionServer implements Runnable {

    private AuctionDatabase dB;
    private ServerSocket serverSock;
    private ServerSocket refServer;
    private Thread t = null;
    private Thread transThread = null;
    private int flag = 1;

    public void go() {
        try {
            serverSock = new ServerSocket(5000);
            dB = new AuctionDatabase();
            dB.transQuery();
            transThread = new Thread(new Transaction());
            transThread.start();
            while (flag == 1) {
                Socket clientSocket = serverSock.accept();
                t = new Thread(new ClientHandler(clientSocket));
                t.start();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    } // close go


    public void run() {
        this.go();
    }

    public void stop(){
        flag = 0;
    }

    public void manageO(){
        ManageUI manageUI = new ManageUI(dB);
        manageUI.initiateUI();
        manageUI.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        manageUI.setSize(1035, 510);
        manageUI.setResizable(false);
        manageUI.setVisible(true);
    }
    
    private class Transaction implements Runnable {

        Timer timer = new Timer();

        public void run() {
            timer.scheduleAtFixedRate(new serverTimer(), 0, 60000L);
        }

        private class serverTimer extends TimerTask {

            SimpleDateFormat formatter = new SimpleDateFormat("HH mm");

            @Override
            public void run() {
                Calendar currentTime = Calendar.getInstance();
                if(formatter.format(currentTime.getTime()).equalsIgnoreCase("00 00")){
                    dB.transQuery();
                }
            }
        }
    }

    private class ClientHandler implements Runnable {

        User user;
        InputStream input;
        OutputStream output;
        BufferedInputStream reader;
        BufferedOutputStream writer;
        ObjectOutputStream objectSender;
        ObjectInputStream objectReader;
        BufferedReader stringReader;
        PrintWriter stringWriter;
        Socket sock;

        public ClientHandler(Socket clientSocket) {
            try {
                sock = clientSocket;

                input = sock.getInputStream();
                reader = new BufferedInputStream(input);
                reader.mark(1000);

                stringReader = new BufferedReader(new InputStreamReader(sock.getInputStream()));

                output = sock.getOutputStream();
                writer = new BufferedOutputStream(output);
                objectSender = new ObjectOutputStream(writer);
                stringWriter = new PrintWriter(output);

            } catch (Exception ex) {
                ex.printStackTrace();
            }
        } // close constructor

        public void run() {
            try {
                String message;

                while ((message = stringReader.readLine()) != null) {
                    processMessage(message);
                }// close while
            } catch (Exception ex) {
                System.out.println("Connection closed");
            }
        } // close run

        public void processMessage(String lineToProcess) {
            StringTokenizer st = new StringTokenizer(lineToProcess, ";");
            String menu = st.nextToken();

            if (menu.equalsIgnoreCase("login")) {//process login
                String username = st.nextToken();
                String pass = st.nextToken();
                user = dB.loginQuery(username, pass);
                try {
                    if (user != null) {
                        stringWriter.println(user.loginString());
                        stringWriter.flush();

                    } else{
                        System.out.println("fail");
                        stringWriter.println("fail");
                        stringWriter.flush();
                    }

                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            } else if (menu.equalsIgnoreCase("register")) {//process register
                User newUser = null;
                try {
                    String regString = stringReader.readLine();
                    st = new StringTokenizer(regString, ";");
                    newUser = new User(st.nextToken(),st.nextToken(),st.nextToken(),st.nextToken(),st.nextToken(),st.nextToken(),st.nextToken());
                } catch (IOException ex) {
                    Logger.getLogger(AuctionServer.class.getName()).log(Level.SEVERE, null, ex);
                }//close try-catch
                if (newUser != null) {
                    boolean regisStatus = dB.registerQuery(newUser);
                    //send data to DB

                    if (regisStatus == true) {
                        stringWriter.println("success");
                        stringWriter.flush();
                    } else {
                        stringWriter.println("fail");
                        stringWriter.flush();
                    }
                }//close inner if
            } else if (menu.equalsIgnoreCase("place")){// process place item
                    Item newItem = null;
                try {

                    if(objectReader == null){
                        objectReader = new ObjectInputStream(reader);
                    }
                    newItem = (Item)objectReader.readUnshared();
                } catch (IOException ex) {
                    Logger.getLogger(AuctionServer.class.getName()).log(Level.SEVERE, null, ex);
                } catch (ClassNotFoundException ex){

                }

                if (newItem != null) {
                    boolean placeStatus = dB.placeItemQuery(newItem);

                    if (placeStatus == true) {
                        stringWriter.println("success");
                        stringWriter.flush();
                    } else {
                        stringWriter.println("fail");
                        stringWriter.flush();
                    }
                    }


            } else if (menu.equalsIgnoreCase("recharge")){
                boolean rechargeStatus = dB.rechargeQuery(st.nextToken(), st.nextToken());

                if (rechargeStatus == true) {
                    stringWriter.println("success");
                    stringWriter.flush();
                } else {
                    stringWriter.println("fail");
                    stringWriter.flush();
                }


            } else if (menu.equalsIgnoreCase("refresh")) {
                try {
                    if(refServer == null){
                        refServer = new ServerSocket(4848);
                    }
                    Socket refClientSocket = refServer.accept();
                    Thread refThread = new Thread(new Refresh(refClientSocket));
                    refThread.start();
                } catch (IOException ex) {
                    Logger.getLogger(AuctionServer.class.getName()).log(Level.SEVERE, null, ex);
                }

                
            } else if (menu.equalsIgnoreCase("bid")) {
                boolean bidStatus = dB.bidQuery(st.nextToken(), st.nextToken(), st.nextToken());

                if(bidStatus == true){
                    stringWriter.println("success");
                }else{
                    stringWriter.println("fail");
                }
                    stringWriter.flush();
            } else if (menu.equalsIgnoreCase("view")){
                String id = st.nextToken();
                Queue<String> viewQ = dB.viewHistoryQuery(id);
                Queue<String> viewTQ = dB.viewTransHistory(id);
                try {
                    int limit = viewQ.size();
                        stringWriter.println(limit);
                        stringWriter.flush();
                    for(int i =0; i<limit; i++){
                        stringWriter.println(viewQ.poll());
                        stringWriter.flush();
                    }

                    limit = viewTQ.size();
                    stringWriter.println(limit);
                    stringWriter.flush();
                    for (int i = 0; i < limit; i++) {
                        stringWriter.println(viewTQ.poll());
                        stringWriter.flush();
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
                //close if

        }//close ProcessMessage


        
        private class Refresh implements Runnable{
            private Socket sock;
            private ObjectOutputStream refSender;
            public Refresh(Socket sock){
                this.sock = sock;
            }
            public void run(){
                try {
                    refSender = new ObjectOutputStream(sock.getOutputStream());
                } catch (IOException ex) {
                    Logger.getLogger(AuctionServer.class.getName()).log(Level.SEVERE, null, ex);
                }
                Queue<Item> itemQ = null;
                try {

                    /*
                    THIS ONE IS LIKE HISTORY
                     */
                    itemQ = dB.refreshQuery();

                    int limit = itemQ.size();
                    stringWriter.println(limit);
                    stringWriter.flush();

                    for (int i = 0; i < limit;i++) {
                        refSender.reset();
                        refSender.writeUnshared(itemQ.poll());
                        refSender.flush();
                        refSender.reset();
                    }
                    refSender.close();
                    sock.close();

                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
    } // close inner class
}
